package com.mathdroid.gui.main.character;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import com.mathdroid.gui.main.Popup;
import com.mathdroid.gui.main.browser.ItemBrowser;
import com.mathdroid.gui.main.browser.SearchField;
import com.mathdroid.model.EModelObserverEvent;
import com.mathdroid.model.IModelObserver;
import com.mathdroid.model.Model;
import com.mathdroid.model.enums.EItemSlot;
import com.mathdroid.model.enums.EItemType;
import com.mathdroid.model.enums.EModuleProficiency;
import com.mathdroid.model.items.Item;

/**
 * This is a small popup that contains the name of the equiped item and an item
 * browser panel.
 */
public final class ItemSlotPopup extends Popup implements IModelObserver {

	/**
	 * Default UID.
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Button to close the popup.
	 */
	private JButton dispose = new JButton();
	
	/**
	 * Label that shows the name of the equipped item.
	 */
	private JLabel equipped = new JLabel();
	
	/**
	 * The browser panel.
	 */
	private ItemBrowser browser = null;
	
	/**
	 * The scroll pane that contains the browser panel.
	 */
	private JScrollPane scrollPane = null;
	
	/**
	 * The item slot source.
	 */
	private EItemSlot slot = null;

	/**
	 * The type of the source slot.
	 */
	private EItemType type = null;
	
	/**
	 * The module to show in the browser.
	 */
	private EModuleProficiency module = null;
	
	/**
	 * The preferred dimension of the close button.
	 */
	private static final int BUTTON_DIM = 25;
	
	/**
	 * The width of the scroll pane.
	 */
	private static final int SCROLL_PANE_WIDTH = 400;
	
	/**
	 * the height of the scroll pane.
	 */
	private static final int SCROLL_PANE_HEIGHT = 200;

	/**
	 * The width of the search field.
	 */
	private static final int SEARCH_FIELD_WIDTH = 100;

	/**
	 * The height of the search field.
	 */
	private static final int SEARCH_FIELD_HEIGHT = 26;
	
	/**
	 * The weight of "heavy" components.
	 */
	private static final int HEAVY_WEIGHT = 10;

	/**
	 * The space between components..
	 */
	private static final int SPACING = 10;
	
	/**
	 * Create an item slot PopUp.
	 * @param s Items for this source slot should be shown.
	 * @param m The module type. Can be null.
	 * @param t The item type of the source slot.
	 */
	public ItemSlotPopup(final EItemSlot s, 
			final EModuleProficiency m, final EItemType t) {
		super();
		
		this.browser = new ItemBrowser(this, s);
		
		Model.registerObserver(this);
		
		this.slot = s;
		this.module = m;
		this.type = t;
		
		/*
		 * This PopUp was called from an armor / weapon / module slot.
		 */
		switch (this.type) {
			case MODULE:
				Model.getProfile().getItemBrowserModel().setTypeCondition(
						this.module.toString());	
				break;
			case ARMOR:
				Model.getProfile().getItemBrowserModel().setTypeCondition(
						this.slot.toString());	
				break;
			case WEAPON:
				Model.getProfile().getItemBrowserModel().setTypeCondition(
						this.slot.toString());	
				break;
			default:
				break;
		}
		
		this.buildLabel();
		this.buildSearchField();
		this.buildButton();
		this.buildBrowser();
		
		new PopupFocusListener(this);
		
		this.pack();
		
		Model.refreshItemBrowserModel();
		this.browser.requestFocus();
		this.setAlwaysOnTop(true);
		this.setVisible(true);
	}

	/**
	 * Add a search field to the right top.
	 */
	private void buildSearchField() {
		this.getConstraints().insets = new Insets(0, 0, 0, 0);
		this.getConstraints().gridwidth = 1;
		this.getConstraints().gridx = 1;
		this.getConstraints().gridy = 0;
		this.getConstraints().weightx = 0;
		this.getConstraints().weighty = 0;
		this.getConstraints().fill = GridBagConstraints.HORIZONTAL;
		this.getPanel().add(
				new SearchField(SEARCH_FIELD_WIDTH, SEARCH_FIELD_HEIGHT), 
				this.getConstraints());
	}

	/**
	 * Build the item browser panel.
	 */
	private void buildBrowser() {
		this.scrollPane = new JScrollPane(this.browser);
		this.scrollPane.setVerticalScrollBarPolicy(
				ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		this.scrollPane.setHorizontalScrollBarPolicy(
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		this.scrollPane.setPreferredSize(
				new Dimension(SCROLL_PANE_WIDTH, SCROLL_PANE_HEIGHT));
		
		this.getConstraints().insets = new Insets(0, 0, 0, 0);
		this.getConstraints().gridwidth = 3;
		this.getConstraints().gridx = 0;
		this.getConstraints().gridy = 1;
		this.getConstraints().weightx = HEAVY_WEIGHT;
		this.getConstraints().weighty = HEAVY_WEIGHT;
		this.getConstraints().fill = GridBagConstraints.BOTH;
		this.getPanel().add(this.scrollPane, this.getConstraints());
		
		/* Important note: This has to be called _AFTER_ the .add() */
		this.browser.setParentScrollPane(this.scrollPane);
	}

	/**
	 * Build the close button.
	 */
	private void buildButton() {
		final IModelObserver popup = this;
		this.dispose.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent arg0) {
				dispose();
				Model.getProfile().getItemBrowserModel().setRegExFilter("");
				Model.unregisterObserver(popup);
				Model.unregisterObserver(browser);
			}
		});
		
		this.dispose.setIcon(new ImageIcon(this.getClass().getResource(
									"/com/mathdroid/gui/images/cross.png")));
		this.dispose.setPreferredSize(new Dimension(BUTTON_DIM, BUTTON_DIM));
		
		this.getConstraints().insets = new Insets(0, 0, 0, 0);
		this.getConstraints().gridwidth = 1;
		this.getConstraints().gridx = 2;
		this.getConstraints().gridy = 0;
		this.getConstraints().weightx = 0;
		this.getConstraints().weighty = 0;
		this.getConstraints().fill = GridBagConstraints.HORIZONTAL;
		this.getPanel().add(this.dispose, this.getConstraints());
	}

	/**
	 * Build the label that shows the equipped item name.
	 */
	private void buildLabel() {
		this.refreshLabel();
		
		this.getConstraints().insets = new Insets(0, SPACING, 0, SPACING);
		this.getConstraints().gridwidth = 1;
		this.getConstraints().gridx = 0;
		this.getConstraints().gridy = 0;
		this.getConstraints().weightx = HEAVY_WEIGHT;
		this.getConstraints().weighty = 0;
		this.getConstraints().fill = GridBagConstraints.NONE;
		this.getPanel().add(this.equipped, this.getConstraints());
	}

	/**
	 * Refresh the item name in the label.
	 */
	private void refreshLabel() {
		Item i = Model.getProfile().getEquipedItems().get(this.slot);
		
		if (i != null) {
			this.equipped.setText("Equipped: " + i.getName());
		} else {
			this.equipped.setText("Equipped: Nothing");
		}
	}

	@Override
	public void modelChanged(final EModelObserverEvent e) {
		if (e == EModelObserverEvent.PROFILE_LOADED 
				|| e == EModelObserverEvent.ITEM_BROWSER_MODEL_CHANGED) {
			this.browser.refresh();
			this.repaint();
		}
	}
	
	/**
	 * @return the slot
	 */
	public EItemSlot getSlot() {
		return slot;
	}
}
